package com.sailing.xjpb.orm.utils;

import com.sailing.xjpb.common.SailingReflectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.property.access.spi.*;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 解析字段中标记@Column注解的字段
 */
@Slf4j
public class SailingPropertyAccessImpl implements PropertyAccess {

    private final SailingPropertyAccessStrategyImpl strategy;
    private final GetterMethodImpl getter;
    private final SetterMethodImpl setter;

    public SailingPropertyAccessImpl(SailingPropertyAccessStrategyImpl strategy,
                                     Class<?> containerJavaType, String propertyName) {
        this.strategy = strategy;
        Field field = SailingReflectionUtils.getDeclaredField(containerJavaType, f -> {
            Column annotation = f.getAnnotation(Column.class);
            return annotation != null && annotation.name().equals(propertyName);
        });
        if (field == null) {
            throw new PropertyNotFoundException("Could not resolve PropertyAccess for " + propertyName + " on " + containerJavaType);
        }
        String columnProperty = field.getName();
        log.info("resolve PropertyAccess for {} to {} on {}", propertyName, columnProperty, containerJavaType);
        final Method getterMethod = ReflectHelper.findGetterMethod(containerJavaType, columnProperty);
        this.getter = new GetterMethodImpl(containerJavaType, columnProperty, getterMethod);

        final Method setterMethod = ReflectHelper.findSetterMethod(containerJavaType, columnProperty,
                getterMethod.getReturnType());
        this.setter = new SetterMethodImpl(containerJavaType, columnProperty, setterMethod);
    }

    @Override
    public PropertyAccessStrategy getPropertyAccessStrategy() {
        return strategy;
    }

    @Override
    public Getter getGetter() {
        return getter;
    }

    @Override
    public Setter getSetter() {
        return setter;
    }
}
